﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataAccess = Microsoft.MSE.Catalog.Module.Data;
using DTO = Microsoft.MSE.Catalog.Contracts;
using System.Data.SqlClient;
using System.Data;

namespace Microsoft.MSE.Catalog.Module.Business
{
    public class RuntimeServerManager
    {
        public RuntimeServerManager()
        {

        }

        #region Runtime Server  functions
        public static Guid CreateRuntimeServer(DTO.RuntimeServer runtimeServer, SqlTransaction txn, SqlConnection conn)
        {
            Guid epID = DataAccess.Entity.GetIDFromName(runtimeServer.Name, Microsoft.MSE.Catalog.Contracts.EntityClass.RuntimeServer, txn, conn);
            if (epID == Guid.Empty)
            {
                //Note: No change tracking
                return DataAccess.RuntimeServer.CreateRuntimeServer(runtimeServer, txn, conn);
            }
            else
            {
                if (txn != null) txn.Rollback(); //Rollback transaction
                throw new ApplicationException("Runtime Server already exists in the Service Model");
            }

        }

        public static DTO.RuntimeServer UpdateRuntimeServer(DTO.RuntimeServer runtimeServer, SqlTransaction txn, SqlConnection conn)
        {
            Guid ID = DataAccess.Entity.GetIDFromName(runtimeServer.Name, Microsoft.MSE.Catalog.Contracts.EntityClass.RuntimeServer, txn, conn);
            if (ID == Guid.Empty || (ID.CompareTo(runtimeServer.ID) == 0))
            {
                //collect endpoint information (can be isolated from data modifications)
                DTO.EndpointList list = EndpointManager.ListEndpointsForRuntimeServerID(runtimeServer.ID, txn, conn);


                runtimeServer = DataAccess.RuntimeServer.UpdateRuntimeServer(runtimeServer, txn, conn);

                #region Endpoint Association changes
                //remove any endpoint associations that should no longer be
                bool present = false;
                if (list.Endpoints != null)
                {
                    foreach (DTO.EndpointListElement ep in list.Endpoints)
                    {
                        present = false;
                        if (runtimeServer.Endpoints != null)
                        {
                            foreach (DTO.Endpoint xep in runtimeServer.Endpoints)
                            {
                                if (ep.ID == xep.ID)
                                    present = true;
                            }
                        }
                        if (!present)
                        {
                            EndpointManager.RemoveEndpointFromRuntimeServer(ep.ID, runtimeServer.ID, txn, conn);
                        }
                    }
                }
                //Add any new endpoint associations
                if (runtimeServer.Endpoints != null)
                {
                    foreach (DTO.Endpoint xep in runtimeServer.Endpoints)
                    {
                        present = false;
                        if (list.Endpoints != null)
                        {
                            foreach (DTO.EndpointListElement ep in list.Endpoints)
                            {
                                if (ep.ID == xep.ID)
                                {
                                    present = true;
                                    break;
                                }
                            }
                        }
                        if (!present)
                        {
                            if (xep.ID.Equals(Guid.Empty))
                            {
                                xep.ID = EndpointManager.CreateEndpoint(xep, txn, conn);
                            }
                            EndpointManager.AssignEndpointToRuntimeServer(xep.ID, runtimeServer.ID, txn, conn);
                        }
                    }
                }
                #endregion

                //create change record
                DTO.DBEventContext eventContext = ChangeTrackingHelper.GetEventContextForRuntimeServerUpdate(runtimeServer.ID, txn, conn);
                DataAccess.RepositoryChange.Save(eventContext, txn, conn);
            }
            else
            {
                if (txn != null) txn.Rollback(); //Rollback transaction
                throw new ApplicationException("Runtime Server already exists in the Service Model");
            }

            return runtimeServer;
        }
        public static void DeleteRuntimeServer(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            //NOTE: No change tracking implemented here since db integrity requires removing endpoints from runtime first

            DataAccess.RuntimeServer.DeleteRuntimeServer(ID, txn, conn);
        }

        public static DTO.RuntimeServer GetRuntimeServer(Guid runtimeServerID, bool provideWSDL, SqlTransaction txn, SqlConnection conn)
        {
            DTO.RuntimeServer runtimeServer = DataAccess.RuntimeServer.GetRuntimeServer(runtimeServerID, provideWSDL, txn, conn);

            runtimeServer.Endpoints = new List<DTO.Endpoint>();
            DTO.EndpointList endpointList = DataAccess.Endpoint.ListEndpointsForRuntimeServerID(runtimeServerID, txn, conn);
            if (endpointList.Endpoints != null)
            {
                foreach (DTO.EndpointListElement element in endpointList.Endpoints)
                {
                    runtimeServer.Endpoints.Add(EndpointManager.GetEndpoint(element.ID, runtimeServer.ID,runtimeServer.HostName, provideWSDL, txn, conn));
                }
            }
            return runtimeServer;
        }

        public static DTO.RuntimeServerList ListRuntimeServers( SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.RuntimeServer.ListRuntimeServers(txn, conn);
        }

        public static List<DTO.DBEventDataItem> ListRuntimeEventDataForEndpointID(Guid endpointID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.RuntimeServer.ListRuntimeEventDataForEndpointID(endpointID, txn, conn);
        }

        public static List<DTO.DBEventDataItem> ListRuntimeEventDataForResourceID(Guid resourceID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.RuntimeServer.ListRuntimeEventDataForResourceID(resourceID, txn, conn);
        }

        public static List<DTO.DBEventDataItem> ListRuntimeEventDataForOperationID(Guid operationID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.RuntimeServer.ListRuntimeEventDataForOperationID(operationID, txn, conn);
        }

        public static List<DTO.DBEventDataItem> ListRuntimeEventDataForOperationVersionID(Guid operationVersionID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.RuntimeServer.ListRuntimeEventDataForOperationVersionID(operationVersionID, txn, conn);
        }

        public static List<DTO.DBEventDataItem> ListRuntimeEventDataForBindingID(Guid bindingID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.RuntimeServer.ListRuntimeEventDataForBindingID(bindingID, txn, conn);
        }

        public static List<DTO.DBEventDataItem> ListRuntimeEventDataForPolicyID(Guid policyID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.RuntimeServer.ListRuntimeEventDataForPolicyID(policyID, txn, conn);
        }

        public static List<DTO.DBEventDataItem> ListRuntimeEventDataForSystemInstanceID(Guid instanceID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.RuntimeServer.ListRuntimeEventDataForSystemInstanceID(instanceID, txn, conn);
        }

        public static List<DTO.DBEventDataItem> ListRuntimeEventDataForSystemID(Guid systemID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.RuntimeServer.ListRuntimeEventDataForSystemID(systemID, txn, conn);
        }

        public static DTO.RuntimeServerNotificationList ListRuntimeServerNotificationAddresses( SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.RuntimeServer.ListRuntimeServerNotificationAddresses(txn, conn);
        }

        #endregion

        #region Runtime Server Group functions

        public static DTO.RuntimeServerGroup CreateRuntimeServerGroup(DTO.RuntimeServerGroup runtimeServerGroup)
        {

            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Snapshot);

                try
                {
                    runtimeServerGroup.ID = DataAccess.Entity.CreateEntityGroup(runtimeServerGroup.Name, runtimeServerGroup.Description, 0, txn, conn);

                    if (runtimeServerGroup.RuntimeServers != null)
                    {
                        foreach (DTO.RuntimeServerListElement runtimeServer in runtimeServerGroup.RuntimeServers)
                        {
                            DataAccess.Entity.AssignEntityToEntityGroup(runtimeServerGroup.ID, runtimeServer.ID, txn, conn);
                        }
                    }

                    if (txn != null) txn.Commit(); //Commit transaction
                }
                catch (Exception)
                {
                    if (txn != null) txn.Rollback(); //Rollback transaction
                    throw;
                }
            } //Connection is disposed here

            return runtimeServerGroup;
        }

        public static DTO.RuntimeServerGroup UpdateRuntimeServerGroup(DTO.RuntimeServerGroup runtimeServerGroup)
        {
            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Snapshot);

                try
                {

                    DataAccess.Entity.UpdateEntityGroup(runtimeServerGroup.ID, runtimeServerGroup.Name, runtimeServerGroup.Description, txn, conn);


                    List<DTO.RuntimeServerListElement> oldList = DataAccess.RuntimeServer.ListRuntimeServersByGroup(runtimeServerGroup.ID, txn, conn);
                    /// Delete all items from the old list
                    if (oldList != null)
                    {
                        foreach (DTO.RuntimeServerListElement oldListElement in oldList)
                        {
                            DataAccess.Entity.RemoveEntityFromEntityGroup(runtimeServerGroup.ID, oldListElement.ID, txn, conn);
                        }
                    }
                    /// Add all items from the new list
                    if (runtimeServerGroup.RuntimeServers != null)
                    {
                        foreach (DTO.RuntimeServerListElement newListElement in runtimeServerGroup.RuntimeServers)
                        {
                            DataAccess.Entity.AssignEntityToEntityGroup(runtimeServerGroup.ID, newListElement.ID, txn, conn);
                        }
                    }

                    if (txn != null) txn.Commit(); //Commit transaction
                }
                catch (Exception)
                {
                    if (txn != null) txn.Rollback(); //Rollback transaction
                    throw;
                }
            } //Connection is disposed here

            return runtimeServerGroup;
        }

        public static DTO.RuntimeServerGroup GetRuntimeServerGroup(Guid ID)
        {
            DTO.RuntimeServerGroup runtimeServerGroup = new DTO.RuntimeServerGroup();
            DTO.EntityGroup entityGroup = new DTO.EntityGroup();

            entityGroup = DataAccess.Entity.GetEntityGroup(ID, null, null);

            runtimeServerGroup.ID = entityGroup.ID;
            runtimeServerGroup.Name = entityGroup.Name;
            runtimeServerGroup.Description = entityGroup.Description;

            runtimeServerGroup.RuntimeServers = ListRuntimeServersByGroup(ID);

            return runtimeServerGroup;
        }

        public static List<DTO.RuntimeServerListElement> ListRuntimeServersByGroup(Guid entityGroupID)
        {
            return DataAccess.RuntimeServer.ListRuntimeServersByGroup(entityGroupID, null, null);

        }

        #endregion
    }
}
